#pragma once

#include <ddblk/locks/lock_int.h>

typedef struct _spinlock
{
	lkword_t locked;
} _spinlock_t;

typedef void _spinnode_t;

DECL_LOCK(spin)

PARAM_NONULL(1) SAI _spinlock_t *_spin_init(void *ptr, size_t size)
{	
	if (size < sizeof(_spinlock_t)) return NULL;
	_spinlock_t *s = (_spinlock_t *)ptr;
	s->locked = 0;
	return s;
}

PARAM_NONULL(1) SAI void *_spin_destruct(_spinlock_t *s)
{
	PARAM_USED(s);
	return (void *)s;
}

PARAM_NONULL(1) SAI bool_t _spin_lock(_spinlock_t *s, locktoken_t *ptoken, waitcnt_t cnt, 
	INFUN(lock, waitpolicy), const acq_ord_t order)
{
	PARAM_USED(ptoken);
	lkword_t lock_locked = 1;
	lkword_t tmp_lock;
	bool_t bret;
	
	
	tmp_lock = atm_ld(&s->locked);
	do {
		if (LIKELY(tmp_lock == 0))
		{
			if (order == LACQ) bret = cas_acq_s(&s->locked, &tmp_lock, 1);
			else bret = cas_acq_s(&s->locked, &tmp_lock, 1);

			if (bret)
			{
				break;
			}
		}
		/* 锁住且cas失败的情况需要挂入等待队列? 那这个cas必须是强cas呀 */
		else{
			cnt = waitpolicy->waitf(&s->locked, &lock_locked, cnt);
			if (!cnt) { return FALSE; }
			tmp_lock = atm_ld(&s->locked);
		}
	} while (TRUE);
	return TRUE;
}

PARAM_NONULL(1) SAI bool_t _spin_unlock(_spinlock_t *s, locktoken_t token, waitcnt_t cnt, 
	INFUN(lock, waitpolicy),  const rel_ord_t order)
{
	PARAM_USED(token, cnt);
	lkword_t lock_unlocked = 0;

	if (order == RREL)atm_strel(&s->locked, lock_unlocked);
	else atm_st(&s->locked, lock_unlocked);

	/* 通知等待线程 */
	waitpolicy->wakef(&s->locked, &lock_unlocked);
	return TRUE;
}

/* 重试次数限制 */
DEF_LOCK(spin, bounded_spin, OUFUN_OF(spin_wait_bounded))
/* 永远自旋 */
DEF_LOCK(spin, spin, OUFUN_OF(spin_wait))
/* 调度放弃 */
DEF_LOCK(spin, yield_spin, OUFUN_OF(schedyield_wait))
/* futex等待 */
DEF_LOCK(spin, futex_spin, OUFUN_OF(futex_wait))
